/**
 * LinkedLST, Kellen Donohue
 * May 6, 2001
 * JavaObjectPopulator.java - Fills a Java object with the data from the JSON Object 
 */

package edu.washington.cs.labspecimentransport.data;

import java.lang.reflect.Field;
import java.util.Iterator;

import org.json.JSONException;
import org.json.JSONObject;

/**
 * Creates and populates a Java object with JSON data
 * 
 * @author Kellen
 * 
 */
public class JavaObjectPopulator {
	private final String objectPackageName = "edu.washington.cs.labspecimentransport.dataobjects";

	/**
	 * The JSON used to parse the object from
	 */
	private JSONObject sourceJSON;

	@SuppressWarnings("rawtypes")
	/**
	 * The class of the parsed object
	 */
	private Class objectClass;

	/**
	 * The object parsed from the JSON
	 */
	private Object obj;

	/**
	 * Create a new Java Object populator
	 * 
	 * @param obj
	 *            The JSON object to build the new object from
	 * @throws ClassNotFoundException
	 *             If the JSON class can't be found
	 * @throws JSONException
	 *             If the JSON object can't be parsed
	 * @throws InstantiationException
	 *             If a new Java object can't be created
	 * @throws IllegalAccessException
	 *             If the Java object fields can't be made accessible
	 * @throws NoSuchFieldException
	 *             If a non-existent field is accessed
	 */
	public JavaObjectPopulator(JSONObject obj) throws ClassNotFoundException,
			JSONException, IllegalAccessException, InstantiationException,
			NoSuchFieldException {
		// The class name is the key of the JSON object
		String className = obj.keys().next();
		this.objectClass = Class.forName(objectPackageName + '.'
				+ RailsModel.javaifyName(className));
		this.sourceJSON = obj.getJSONObject(className);

		// Create an instance of the Java object
		Object finalObj = objectClass.newInstance();

		// Populate each field
		Iterator<String> objectFields = this.sourceJSON.keys();
		while (objectFields.hasNext()) {
			String key = objectFields.next();
			Field field = this.objectClass.getDeclaredField(key);
			Object val = this.sourceJSON.get(key);
			// Don't update null values, these can't be stored in some java
			// types, also ignore updated_at and created_at since we
			// don't care about those
			if (val == JSONObject.NULL
					|| field.getType().toString().contains("java.util.Date")) {
				continue;
			}
			field.setAccessible(true);
			try {
				field.set(finalObj, val);
			} catch (java.lang.IllegalArgumentException ex) {
				// Record that we couldn't populate the field
				System.err.println("Couldn't set " + field + " to "
						+ this.sourceJSON.get(key));
			}
		}
		this.obj = finalObj;
	}

	/**
	 * Get the object parsed from the given JSON
	 * 
	 * @return The parsed object
	 */
	public Object getObject() {
		return this.obj;
	}
}
